package io.shuttle.mbe.api

import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.Value2Function
import io.shuttle.mbe.api.types.Value3Function
import io.shuttle.mbe.api.types.VoidFunction


interface Input {
    ////////////////////
    // Input - IME
    ////////////////////
    /**
     * Use the `Browser.input.ime` API to implement a custom IME for Chrome OS. This allows your extension to handle keystrokes, set the composition, and manage the candidate window.
     *
     * Permissions: "input"
     * @platform ChromeOS only
     */
    interface Ime {
        /**
         * Adds the provided menu items to the language menu when this IME is active.
         */
        fun setMenuItems(parameters: ImeParameters, callback: VoidFunction)

        /**
         * Commits the provided text to the current input.
         * @param callback Called when the operation completes with a boolean indicating if the text was accepted or not. On failure, Browser.runtime.lastError is set.
         */
        fun commitText(parameters: CommitTextParameters, callback: Value1Function<Boolean>? = null)

        /**
         * Sets the current candidate list. This fails if this extension doesn't own the active IME
         * @param callback Called when the operation completes.
         */
        fun setCandidates(
            parameters: CandidatesParameters,
            callback: Value1Function<Boolean>? = null
        )

        /**
         * Set the current composition. If this extension does not own the active IME, this fails.
         * @param callback Called when the operation completes with a boolean indicating if the text was accepted or not. On failure, Browser.runtime.lastError is set.
         */
        fun setComposition(
            parameters: CompositionParameters,
            callback: Value1Function<Boolean>? = null
        )

        /**
         * Updates the state of the MenuItems specified
         * @param callback Called when the operation completes
         */
        fun updateMenuItems(parameters: MenuItemParameters, callback: VoidFunction)

        /**
         * Shows/Hides an assistive window with the given properties.
         * @param parameters
         * @param callback Called when the operation completes.
         */
        fun setAssistiveWindowProperties(
            parameters: SetAssitiveWindowProperties,
            callback: Value1Function<Boolean>? = null,
        )

        /**
         * Highlights/Unhighlights a button in an assistive window.
         * @param parameters
         * @param callback Called when the operation completes. On failure, Browser.runtime.lastError is set.
         */
        fun setAssistiveWindowButtonHighlighted(
            parameters: SetAssistiveWindowButtonHighlighted,
            callback: VoidFunction,
        )

        /**
         * Sets the properties of the candidate window. This fails if the extension doesn't own the active IME
         * @param callback Called when the operation completes.
         */
        fun setCandidateWindowProperties(
            parameters: CandidateWindowParameter,
            callback: Value1Function<Boolean>? = null,
        )

        /**
         * Clear the current composition. If this extension does not own the active IME, this fails.
         * @param callback Called when the operation completes with a boolean indicating if the text was accepted or not. On failure, Browser.runtime.lastError is set.
         */
        fun clearComposition(
            parameters: ClearCompositionParameters,
            callback: Value1Function<Boolean>? = null,
        )

        /**
         * Set the position of the cursor in the candidate window. This is a no-op if this extension does not own the active IME.
         * @param callback Called when the operation completes
         */
        fun setCursorPosition(
            parameters: CursorPositionParameters,
            callback: Value1Function<Boolean>? = null,
        )

        /**
         * Sends the key events. This function is expected to be used by virtual keyboards. When key(s) on a virtual keyboard is pressed by a user, this function is used to propagate that event to the system.
         * @since Chrome 33
         * @param callback Called when the operation completes.
         */
        fun sendKeyEvents(parameters: SendKeyEventParameters, callback: VoidFunction)

        /**
         * Hides the input view window, which is popped up automatically by system. If the input view window is already hidden, this function will do nothing.
         * @since Chrome 34
         */
        fun hideInputView()

        /**
         * Deletes the text around the caret.
         * @since Chrome 27
         */
        fun deleteSurroundingText(
            parameters: DeleteSurroundingTextParameters,
            callback: VoidFunction
        )

        /**
         * Indicates that the key event received by onKeyEvent is handled. This should only be called if the onKeyEvent listener is asynchronous.
         * @since Chrome 25
         * @param requestId Request id of the event that was handled. This should come from keyEvent.requestId
         * @param response True if the keystroke was handled, false if not
         */
        fun keyEventHandled(requestId: String, response: Boolean)

        /** This event is sent when focus leaves a text box. It is sent to all extensions that are listening to this event, and enabled by the user.
         * @param contextID */
        var onBlur: Events.Event<Value1Function<Number>>;

        /** This event is sent when a button in an assistive window is clicked. */
        var onAssistiveWindowButtonClicked: Events.Event<Value1Function<AssistiveWindowButtonClickedDetails>>;

        /** This event is sent if this extension owns the active IME.
         * @param engineID
         * @param candidateID
         * @param button */
        var onCandidateClicked: Events.Event<Value3Function<String, Number, String>>;

        /** This event is sent if this extension owns the active IME.
         * @param engineID
         * @param keyData
         * @param requestId */
        var onKeyEvent: Events.Event<Value3Function<String, KeyboardEvent, String>>;

        /** This event is sent when an IME is deactivated. It signals that the IME will no longer be receiving onKeyPress events.
         * @param engineID */
        var onDeactivated: Events.Event<Value1Function<String>>;

        /** This event is sent when the properties of the current InputContext change, such as the type. It is sent to all extensions that are listening to this event, and enabled by the user. */
        var onInputContextUpdate: Events.Event<Value1Function<InputContext>>;

        /** This event is sent when an IME is activated. It signals that the IME will be receiving onKeyPress events.
         * @param engineID
         * @param screen */
        var onActivate: Events.Event<Value2Function<String, String>>;

        /** This event is sent when focus enters a text box. It is sent to all extensions that are listening to this event, and enabled by the user. */
        var onFocus: Events.Event<Value1Function<InputContext>>;

        /** Called when the user selects a menu item
         * @param engineID
         * @param name*/
        var onMenuItemActivated: Events.Event<Value2Function<String, String>>;

        /**
         * Called when the editable string around caret is changed or when the caret position is moved. The text length is limited to 100 characters for each back and forth direction.
         * @since Chrome 27
         * @param engineID
         */
        var onSurroundingTextChanged: Events.Event<Value2Function<String, SurroundingTextInfo>>;

        /**
         * This event is sent when chrome terminates ongoing text input session.
         * @since Chrome 29
         * @param engineID
         */
        var onReset: Events.Event<Value1Function<String>>;

        /** See http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent */
        data class KeyboardEvent(
            /**
             * Optional.
             * Whether or not the SHIFT key is pressed.
             */
            var shiftKey: Boolean?,
            /**
             * Optional.
             * Whether or not the ALT key is pressed.
             */
            var altKey: Boolean?,
            /**
             * Optional.
             * Whether or not the ALTGR key is pressed.
             * @since Chrome 79
             */
            var altgrKey: Boolean?,
            /**
             * Optional.
             * The ID of the request. Use the requestId param from the onKeyEvent event instead.
             * @deprecated since Chrome 79.
             */
            var requestId: String?,
            /** Value of the key being pressed */
            var key: String,
            /**
             * Optional.
             * Whether or not the CTRL key is pressed.
             */
            var ctrKey: Boolean?,
            /** One of keyup or keydown. */
            var type: String,
            /**
             * Optional.
             * The extension ID of the sender of this keyevent.
             * @since Chrome 34
             */
            var extensionId: String?,
            /**
             * Optional.
             * Value of the physical key being pressed. The value is not affected by current keyboard layout or modifier state.
             * @since Chrome 26
             */
            var code: String,
            /**
             * Optional.
             * The deprecated HTML keyCode, which is system- and implementation-dependent numerical code signifying the unmodified identifier associated with the key pressed.
             * @since Chrome 37
             */
            var keyCode: Number?,
            /**
             * Optional.
             * Whether or not the CAPS_LOCK is enabled.
             * @since Chrome 29
             */
            var capsLock: Boolean?,
        )

        /**
         * The auto-capitalize type of the text field.
         * @since Chrome 69
         */
        enum class AutoCapitalizeType {
            characters,
            words,
            sentences
        }

        /** Describes an input Context */
        data class InputContext(
            /** This is used to specify targets of text field operations. This ID becomes invalid as soon as onBlur is called. */
            var contextID: Number,
            /** Type of value this text field edits, (Text, Number, URL, etc) */
            var type: String,
            /**
             * Whether the text field wants auto-correct.
             * @since Chrome 40
             */
            var autoCorrect: Boolean,
            /**
             * Whether the text field wants auto-complete.
             * @since Chrome 40
             */
            var autoComplete: Boolean,
            /**
             * Whether the text field wants spell-check.
             * @since Chrome 40
             */
            var spellCheck: Boolean,
            /**
             * The auto-capitalize type of the text field.
             * @since Chrome 69
             */
            var autoCapitalize: AutoCapitalizeType,
            /**
             * Whether text entered into the text field should be used to improve typing suggestions for the user.
             * @since Chrome 68
             */
            var shouldDoLearning: Boolean,
        )

        /**
         * A menu item used by an input method to interact with the user from the language menu.
         * @since Chrome 30
         */
        data class MenuItem(
            /** String that will be passed to callbacks referencing this MenuItem. */
            var id: String,
            /** Optional. Text displayed in the menu for this item. */
            var label: String?,
            /** Optional. The type of menu item. */
            var style: String?,
            /** Optional. Indicates this item is visible. */
            var visible: Boolean?,
            /** Indicates this item should be drawn with a check. */
            var checked: Boolean?,
            /** Indicates this item is enabled. */
            var enabled: Boolean?
        )

        data class ImeParameters(
            /** MenuItems to use. */
            var items: List<MenuItem>,
            /** ID of the engine to use */
            var engineID: String,
        )

        data class CommitTextParameters(
            /** The text to commit */
            var text: String,
            /** ID of the context where the text will be committed */
            var contextID: Number,
        )

        data class CandidateUsage(
            /** The title string of details description. */
            var title: String,
            /** The body string of detail description. */
            var body: String,
        )

        data class CandidateTemplate(
            var candidate: String,
            /** The candidate's id */
            var id: Number,
            /**
             * Optional.
             * The id to add these candidates under
             */
            var parentId: Number?,
            /**
             * Optional.
             * Short string displayed to next to the candidate, often the shortcut key or index
             */
            var label: String?,
            /**
             * Optional.
             * Additional text describing the candidate
             */
            var annotation: String?,
            /**
             * Optional.
             * The usage or detail description of word.
             */
            var usage: CandidateUsage?
        )

        data class CandidatesParameters(
            /** ID of the context that owns the candidate window. */
            var contextID: Number,
            /** List of candidates to show in the candidate window */
            var candidates: List<CandidateTemplate>
        )

        data class CompositionParameterSegment(
            /** Index of the character to start this segment at */
            var start: Number,
            /** Index of the character to end this segment after. */
            var end: Number,
            /** The type of the underline to modify this segment. */
            var style: String
        )

        data class CompositionParameters(
            /** ID of the context where the composition text will be set */
            var contextID: Number,
            /** Text to set */
            var text: String,
            /** Optional. List of segments and their associated types. */
            var segments: List<CompositionParameterSegment>?,
            /** Position in the text of the cursor. */
            var cursor: Number,
            /** Optional. Position in the text that the selection starts at. */
            var selectionStart: Number?,
            /** Optional. Position in the text that the selection ends at. */
            var selectionEnd: Number?
        )

        data class MenuItemParameters(
            var items: List<MenuItem>,
            var engineID: String
        )

        /** Type of the assistive window. */
        enum class AssistiveWindowType {
            undo
        }

        /** ID of a button in an assistive window. */
        enum class AssistiveWindowButton {
            undo,
            addToDictionary
        }

        /** Properties of an assistive window. */
        data class AssistiveWindowProperties(
            var type: AssistiveWindowType,
            var visible: Boolean,
            var announceString: String?
        )

        data class SetAssitiveWindowProperties(
            var contextID: Number,
            var properties: AssistiveWindowProperties
        )

        data class SetAssistiveWindowButtonHighlighted(
            var contextID: Number,
            var buttonID: AssistiveWindowButton,
            var windowType: AssistiveWindowType,
            var announceString: String?,
            var highlighted: Boolean
        )

        data class CandidateWindowParameterProperties(
            /**
             * Optional.
             * True to show the cursor, false to hide it.
             */
            var cursorVisible: Boolean?,
            /**
             * Optional.
             * True if the candidate window should be rendered vertical, false to make it horizontal.
             */
            var vertical: Boolean?,
            /**
             * Optional.
             * The number of candidates to display per page.
             */
            var pageSize: Number?,
            /**
             * Optional.
             * True to display the auxiliary text, false to hide it.
             */
            var auxiliaryTextVisible: Boolean?,
            /**
             * Optional.
             * Text that is shown at the bottom of the candidate window.
             */
            var auxiliaryText: String?,
            /**
             * Optional.
             * True to show the Candidate window, false to hide it.
             */
            var visible: Boolean?,
            /**
             * Optional.
             * Where to display the candidate window.
             * @since Chrome 28
             */
            var windowPosition: String?,
            /**
             * Optional.
             * The index of the current chosen candidate out of total candidates.
             * @since Chrome 84
             */
            var currentCandidateIndex: Number?,
            /**
             * Optional.
             * The total number of candidates for the candidate window.
             * @since Chrome 84
             */
            var totalCandidates: Number?
        )

        data class CandidateWindowParameter(
            var engineID: String,
            var properties: CandidateWindowParameterProperties
        )

        data class ClearCompositionParameters(
            /** ID of the context where the composition will be cleared */
            var contextID: Number
        )

        data class CursorPositionParameters(
            /** ID of the candidate to select. */
            var candidateID: Number,
            /** ID of the context that owns the candidate window. */
            var contextID: Number
        )

        data class SendKeyEventParameters(
            /** ID of the context where the key events will be sent, or zero to send key events to non-input field. */
            var contextID: Number,
            /** Data on the key event. */
            var keyData: List<KeyboardEvent>
        )

        data class DeleteSurroundingTextParameters(
            /** ID of the engine receiving the event. */
            var engineID: String,
            /** ID of the context where the surrounding text will be deleted. */
            var contextID: Number,
            /** The offset from the caret position where deletion will start. This value can be negative. */
            var offset: Number,
            /** The number of characters to be deleted */
            var length: Number
        )

        data class SurroundingTextInfo(
            /** The text around cursor. */
            var text: String,
            /** The ending position of the selection. This value indicates caret position if there is no selection. */
            var focus: Number,
            /** The beginning position of the selection. This value indicates caret position if is no selection. */
            var anchor: Number
        )

        data class AssistiveWindowButtonClickedDetails(
            /** The ID of the button clicked. */
            var buttonID: AssistiveWindowButton,
            /** The type of the assistive window. */
            var windowType: AssistiveWindowType
        )
    }
}